﻿// Netris. A free, open source Tetris(tm) clone
// Copyright (C) 2005  Parez Timothy
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

using System;
using SdlDotNet;
using SdlDotNet.Sprites;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.IO;
using System.Net;

namespace Beaglebits.Games.Netris
{
	/// <summary>
	/// Description of GameScreen.
	/// </summary>
	internal class GameScreen
	{
        //Flags
		private bool close = false;
		private bool started = false;
		private bool processing = false;		
		private bool isdropping = false;		
		//private bool enableBackgroundMusic = false; //first step is a switch
		private bool paused = false;

        //Settings
		private int baseInterval = 2000;
		
        //Blocks
		private Block currentBlock;
		private Block nextBlock;
		
		private Point nextBlockPosition;
		
		private System.Windows.Forms.Timer eventTimer;
		
		//private Music backgroundMusic;
		private Sound rotateSound;
		
        //Dimensions
        int width;
        int height;



		internal GameScreen()
		{
            string soundPath = Path.Combine(Program.ApplicationDirectory, "sounds");
			soundPath = Path.Combine(soundPath,"rotate.wav");
			this.rotateSound = new Sound(soundPath);
		}
		
		internal void Show()
		{
            //Paths
            string imagePath = Path.Combine(Program.ApplicationDirectory, "blocks");
            string fontPath = Path.Combine(Program.ApplicationDirectory, "fonts");

			//Set up the GameField
			GameField.SquareImages[0] = (Bitmap)Bitmap.FromFile(Path.Combine(imagePath,"darkgreen.png"));
			GameField.SquareImages[1] = (Bitmap)Bitmap.FromFile(Path.Combine(imagePath,"blue.png"));
			GameField.SquareImages[2] = (Bitmap)Bitmap.FromFile(Path.Combine(imagePath,"green.png"));
			GameField.SquareImages[3] = (Bitmap)Bitmap.FromFile(Path.Combine(imagePath,"orange.png"));
			GameField.SquareImages[4] = (Bitmap)Bitmap.FromFile(Path.Combine(imagePath,"purple.png"));
			GameField.SquareImages[5] = (Bitmap)Bitmap.FromFile(Path.Combine(imagePath,"red.png"));
			GameField.SquareImages[6] = (Bitmap)Bitmap.FromFile(Path.Combine(imagePath,"yellow.png"));

            this.width = (GameField.SquareImages[0].Width * GameField.Width) + 200;
            this.height = (GameField.SquareImages[0].Height * GameField.Height);

            GameField.GameFieldSurface = Video.SetVideoModeWindow(this.width,this.height);
            GameField.BackgroundColor = Color.Black;
        	GameField.Init(Path.Combine(fontPath,"vera.ttf"));
      	   
        	//Set the position of the nextBlock
        	this.nextBlockPosition = new Point(this.width - 150,20);
            
        	
			//Set Video Options
            Video.WindowCaption = String.Concat(Program.ApplicationName, " v", Program.ApplicationVersion);
						
			//Create the timer , as I don't trust the SDL.TickEvent
			//TODO: Update this, as we are now usin SDL.NET 4.x
			this.eventTimer = new System.Windows.Forms.Timer();
			this.eventTimer.Tick += new EventHandler(this.OnTickEvent);
			
			//Hook up the events
			Events.KeyboardUp += new KeyboardEventHandler(this.OnKeyboardUp);
			Events.KeyboardDown += new KeyboardEventHandler(this.OnKeyboardDown);
			
			//Clear the GameField
			GameField.Clear();
					
			while (!close)
			{
				while(Events.Poll()){};
			}
			
			//Let's be nice and clean up the event handlers
			Events.KeyboardUp -= new KeyboardEventHandler(this.OnKeyboardUp);
			Events.KeyboardDown -= new KeyboardEventHandler(this.OnKeyboardDown);
		}
		
		private void startGame()
		{
			//Flag the game as started
			this.started = true;
			Video.WindowCaption = "Netris [Started]";
			
			//Clear the gamefield
			GameField.Clear();
			
			//Get the first blog
			this.getBlock();
			
			//Set the timer properties
			//Events.TicksPerSecond = 1;
			Events.Fps = 1;
			
			//Start the timer
            this.eventTimer.Interval = this.baseInterval;
			this.eventTimer.Start();
		}
		
		private void stopGame()
		{
			//Stop the timer
			this.eventTimer.Stop();
			
			//Flag the game as stopped
			this.started = false;
			
			Video.WindowCaption = "Netris [Game Over]";

            this.submitScores();
		}

        /// <summary>
        /// Experimental
        /// </summary>
        private void submitScores()
        {
            if (GameField.score < 100)
                return;


            InputForm nickInput = new InputForm();
            DialogResult result = nickInput.ShowDialog();

            if (result == DialogResult.OK)
            {
                try
                {
                    WebRequest request = HttpWebRequest.Create(String.Format("http://www.netris.be/placeholder/placeholder/p.php?n={0}&i={1}&d={2}&v={3}&s={4}&l={5}&e={6}&r={7}",
                                                                nickInput.Nickname, "0.0.0.0", Guid.NewGuid().ToString(), Program.ApplicationVersion, GameField.Score,
                                                                GameField.level, GameField.Lines, GameField.drops));
                    request.BeginGetResponse(null, null);
                }
                catch
                {
                    //don't do anything yet, experimental remember
                }
            }
        }
		
		private void getBlock()
		{
			this.isdropping = false;
        	this.currentBlock = null; //Don't kill it as we don't want it to disapair
            
        	if (this.nextBlock == null)
        	{
        		this.currentBlock = new Block(new Point(GameField.SquareImages[0].Width * 6, 0),GameField.GameFieldSurface);
        	}
        	else
        	{
        		//Copy the nextBlock into the currentBlock
        		this.currentBlock = new Block(new Point(GameField.SquareImages[0].Width * 6, 0),this.nextBlock.BlockType,GameField.GameFieldSurface);
        		
        		//Dispose of the old nextBlock
        		this.nextBlock.Hide();
        		this.nextBlock = null;     
        	}
        	
        	this.currentBlock.Show();
            
            this.nextBlock = new Block(this.nextBlockPosition,GameField.GameFieldSurface); 
            this.nextBlock.Show();
		}	
		
		public void OnKeyboardDown(object sender, KeyboardEventArgs e)
		{
            //Escape should always be allowed:
            if (e.Key == Key.Escape)
            {
                if(this.started || this.paused)
                    this.stopGame();
             
                this.close = true;
                return;
            }

            //Don't accept any other keys if paused, also accept F3
			if (this.paused && e.Key != Key.F3)
			{
				return;
			}
										
			switch (e.Key)
			{
                case Key.F3:
                    if (this.started)
                    {
                        this.paused = !this.paused;
                        Video.WindowCaption = "Netris " + (this.paused ? "[Paused]" : "[Started]");

                        return;
                    }
                    break;

				case Key.S:
                    //Do nothing
				break;
				case Key.F1:
					this.startGame();
					break;
				case Key.F2:
					this.stopGame();
				break;
				case Key.LeftArrow:
					if (this.started && !this.isdropping)
					{				
					//	this.rotateSound.Play().Volume = 8;	
						this.currentBlock.Left();
					}
				break;
				case Key.RightArrow:
					if (this.started && !this.isdropping)
					{
						//this.rotateSound.Play().Volume = 8;	
						this.currentBlock.Right();
					}
				break;
				case Key.UpArrow:
					 if (this.started && !this.isdropping)
					 {
					 	//this.rotateSound.Play().Volume = 8;		
					 	this.currentBlock.Rotate();					 	
					 }
					 
				break;
				case Key.DownArrow:
					 if (this.started && !this.isdropping)
					 {
					 	//this.rotateSound.Play().Volume = 8;	
					 	this.currentBlock.Down();
					 }
				break;
				case Key.Space:
					 if (this.started && !this.isdropping)
					 {
					 	this.isdropping = true;
					 	
					 	int downs = 0;
                    	while (this.currentBlock.Down())
                    	{
                    		//Count the ammount of times the block actually goes down
                    		downs++;
                    	}
                    
                    	//If the ammount is at least one, this is a drop
                    	if (downs > 0) GameField.drops++;
                    
                    	//Drop more to score more
                    	GameField.score += downs / 4;
					 }
                break; 
				default:					
				break;
				}
		}
		
		public void OnKeyboardUp(object sender, KeyboardEventArgs e)
		{
								
		}

		public void OnTickEvent(object sender, EventArgs e)
		{
			if (this.paused)
				return;
			
			//The number of erased lines
            int erasedLines;

            //If still being processed return
            if (this.processing) return;

            //Flag that we are processing
            this.processing = true;

            if (!this.currentBlock.Down())
            {
                //Is it game over?
                if (this.currentBlock.Top == 0)
                {
                	this.stopGame();
                }
                else
                {
                    erasedLines = GameField.CheckLines();
                    //If we did erase lines, invalidate the picturebox
                    if (erasedLines > 0)
                    {
                    	GameField.lines += erasedLines;
                    	GameField.score += (GameField.level + 1) * erasedLines * erasedLines * 10;

                        //Bonus for a 4-liner
                        if (erasedLines == 4)
                            GameField.score += (GameField.level * 30);

                    	GameField.level = (erasedLines  + GameField.lines) / 10;
                    	
                    	this.eventTimer.Interval = (this.baseInterval - ((GameField.level + 1) * 100));
                    }
					
                    this.getBlock();
                }
            }
			
            //Update the Score and NextBlock display
            GameField.UpdateScoreView();
            
            //No longer processing
            this.processing = false;			
		}
	}
}
